home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tools
/
jade
/
src
/
buffers.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-09
|
30KB
|
1,147 lines
/* buffers.c -- Buffer handling
Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
This file is part of Jade.
Jade is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Jade is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jade; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "jade.h"
#include "jade_protos.h"
#include <string.h>
#include <stdlib.h>
_PR void buffer_sweep(void);
_PR void buffer_prin(VALUE, VALUE);
_PR TX *first_buffer(void);
_PR void swap_buffers(VW *, TX *);
_PR TX *swap_buffers_tmp(VW *, TX *);
_PR POS *get_tx_cursor(TX *);
_PR int auto_save_buffers(void);
_PR void make_marks_resident(TX *);
_PR void make_marks_non_resident(TX *);
_PR void mark_sweep(void);
_PR int mark_cmp(VALUE, VALUE);
_PR void mark_prin(VALUE, VALUE);
_PR void buffers_init(void);
_PR void buffers_kill(void);
/*
* Chain of all allocated TXs.
*/
_PR TX *buffer_chain;
TX *buffer_chain;
VALUE sym_auto_save_function, sym_leading, sym_all;
_PR VALUE cmd_make_buffer_name(VALUE);
DEFUN("make-buffer-name", cmd_make_buffer_name, subr_make_buffer_name, (VALUE rawName), V_Subr1, DOC_make_buffer_name) /*
::doc:make_buffer_name::
make-buffer-name NAME
Construct a unique buffer-name from NAME.
::end:: */
{
int suffix = 1;
DECLARE1(rawName, STRINGP);
while(TRUE)
{
u_char buf[256];
u_char *thistry;
TX *tx = buffer_chain;
if(suffix != 1)
{
sprintf(buf, "%s<%d>", VSTR(rawName), suffix);
thistry = buf;
}
else
thistry = VSTR(rawName);
while(tx)
{
if(tx->tx_BufferName && !strcmp(thistry, VSTR(tx->tx_BufferName)))
break;
tx = tx->tx_Next;
}
if(!tx)
{
if(suffix == 1)
return(rawName);
return(string_dup(buf));
}
suffix++;
}
}
_PR VALUE cmd_make_buffer(VALUE, VALUE, VALUE);
DEFUN("make-buffer", cmd_make_buffer, subr_make_buffer, (VALUE name, VALUE oldTx, VALUE litName), V_Subr3, DOC_make_buffer) /*
::doc:make_buffer::
make-buffer NAME
Return a new buffer, it's name is the result of (make-buffer-name NAME).
::end:: */
{
TX *tx;
DECLARE1(name, STRINGP);
if(!BUFFERP(oldTx))
{
if(curr_vw)
oldTx = VAL(curr_vw->vw_Tx);
else
oldTx = NULL;
}
if((tx = mycalloc(sizeof(TX))) && clear_line_list(tx))
{
tx->tx_Type = V_Buffer;
tx->tx_Next = buffer_chain;
buffer_chain = tx;
data_after_gc += sizeof(TX);
tx->tx_BufferName = NILP(litName) ? cmd_make_buffer_name(name) : name;
if(tx->tx_BufferName)
{
tx->tx_FileName = null_string;
tx->tx_MinorModeNameList = sym_nil;
tx->tx_MinorModeNameString = null_string;
tx->tx_SavedBlockStatus = -1;
tx->tx_TabSize = 8;
tx->tx_LocalVariables = sym_nil;
tx->tx_GlyphTable = oldTx ? VTX(oldTx)->tx_GlyphTable
: cmd_default_glyph_table();
tx->tx_LastSaveTime = sys_time();
tx->tx_UndoList = sym_nil;
tx->tx_ToUndoList = NULL;
tx->tx_UndoneList = sym_nil;
return(VAL(tx));
}
}
return(NULL);
}
_PR VALUE cmd_destroy_buffer(VALUE);
DEFUN("destroy-buffer", cmd_destroy_buffer, subr_destroy_buffer, (VALUE tx), V_Subr1, DOC_destroy_buffer) /*
::doc:destroy_buffer::
destory-buffer BUFFER
Throw away everything associated with buffer. All resident marks are made
non-resident.
::end:: */
{
DECLARE1(tx, BUFFERP);
make_marks_non_resident(VTX(tx));
clear_line_list(VTX(tx));
VTX(tx)->tx_FileName = null_string;
VTX(tx)->tx_BufferName = null_string;
VTX(tx)->tx_ModeName = NULL;
VTX(tx)->tx_MinorModeNameList = sym_nil;
VTX(tx)->tx_MinorModeNameString = null_string;
VTX(tx)->tx_Changes = 0;
VTX(tx)->tx_LocalVariables = sym_nil;
VTX(tx)->tx_GlyphTable = cmd_default_glyph_table();
VTX(tx)->tx_Flags |= TXFF_RDONLY | TXFF_REFRESH_ALL | TXFF_NO_UNDO;
VTX(tx)->tx_UndoList = sym_nil;
VTX(tx)->tx_ToUndoList = NULL;
VTX(tx)->tx_UndoneList = sym_nil;
#if 0
sm_flush(&main_strmem);
#endif
return(sym_t);
}
void
buffer_sweep(void)
{
TX *tx = buffer_chain;
buffer_chain = NULL;
while(tx)
{
TX *nxt = tx->tx_Next;
if(!GC_MARKEDP(VAL(tx)))
{
make_marks_non_resident(tx);
kill_line_list(tx);
myfree(tx);
}
else
{
GC_CLR(VAL(tx));
tx->tx_Next = buffer_chain;
buffer_chain = tx;
}
tx = nxt;
}
}
void
buffer_prin(VALUE strm, VALUE obj)
{
stream_puts(strm, "#<buffer ", -1, FALSE);
stream_puts(strm, VSTR(VTX(obj)->tx_BufferName), -1, TRUE);
stream_putc(strm, '>');
}
TX *
first_buffer(void)
{
TX *tx;
if(!curr_vw)
{
curr_vw = VWIN(cmd_make_window(sym_nil, sym_nil, sym_nil, sym_nil));
if(!curr_vw)
return(NULL);
}
tx = VTX(cmd_make_buffer(MKSTR("*jade*"), sym_nil, sym_t));
if(tx)
{
swap_buffers(curr_vw, tx);
#ifndef NOSCRLBAR
sys_update_scroller(curr_vw);
#endif
return(tx);
}
return(NULL);
}
/*
* Makes `new' the file being shown in window `vw'
*/
void
swap_buffers(VW *vw, TX *new)
{
TX *old = vw->vw_Tx;
if(old != new)
{
if(old)
{
old->tx_SavedCPos = vw->vw_CursorPos;
old->tx_SavedWPos = vw->vw_DisplayOrigin;
old->tx_SavedBlockPos[0] = vw->vw_BlockS;
old->tx_SavedBlockPos[1] = vw->vw_BlockE;
old->tx_SavedBlockStatus = vw->vw_BlockStatus;
}
vw->vw_Tx = new;
vw->vw_CursorPos = new->tx_SavedCPos;
vw->vw_DisplayOrigin = new->tx_SavedWPos;
vw->vw_BlockS = new->tx_SavedBlockPos[0];
vw->vw_BlockE = new->tx_SavedBlockPos[1];
vw->vw_BlockStatus = new->tx_SavedBlockStatus;
vw->vw_LastRefTx = NULL;
}
}
/*
* "nd" means non-destructive. refcount's of buffers are not changed and
* previous buffer shown is returned.
* This is intended to allow *temporary* switching of buffers before
* reinstalling the original.
* ** this is kind of obsolete but never mind **
*/
TX *
swap_buffers_tmp(VW *vw, TX *new)
{
TX *old = vw->vw_Tx;
if(old != new)
{
if(old)
{
old->tx_SavedCPos = vw->vw_CursorPos;
old->tx_SavedWPos = vw->vw_DisplayOrigin;
old->tx_SavedBlockPos[0] = vw->vw_BlockS;
old->tx_SavedBlockPos[1] = vw->vw_BlockE;
old->tx_SavedBlockStatus = vw->vw_BlockStatus;
}
vw->vw_Tx = new;
vw->vw_CursorPos = new->tx_SavedCPos;
vw->vw_DisplayOrigin = new->tx_SavedWPos;
vw->vw_BlockS = new->tx_SavedBlockPos[0];
vw->vw_BlockE = new->tx_SavedBlockPos[1];
vw->vw_BlockStatus = new->tx_SavedBlockStatus;
}
return(old);
}
_PR VALUE cmd_get_file_buffer(VALUE);
DEFUN("get-file-buffer", cmd_get_file_buffer, subr_get_file_buffer, (VALUE name), V_Subr1, DOC_get_file_buffer) /*
::doc:get_file_buffer::
get-file-buffer NAME
Scan all buffers for one containing the file NAME.
::end:: */
{
TX *tx = buffer_chain;
DECLARE1(name, STRINGP);
while(tx)
{
if(same_files(VSTR(name), VSTR(tx->tx_FileName)))
return(VAL(tx));
tx = tx->tx_Next;
}
return(sym_nil);
}
_PR VALUE cmd_get_buffer(VALUE);
DEFUN("get-buffer", cmd_get_buffer, subr_get_buffer, (VALUE name), V_Subr1, DOC_get_buffer) /*
::doc:get_buffer::
get-buffer NAME
Scan all buffers for one whose name is NAME.
::end:: */
{
TX *tx = buffer_chain;
if(BUFFERP(name))
return(name);
DECLARE1(name, STRINGP);
while(tx)
{
if(!strcmp(VSTR(name), VSTR(tx->tx_BufferName)))
return(VAL(tx));
tx = tx->tx_Next;
}
return(sym_nil);
}
POS *
get_tx_cursor(TX *tx)
{
VW *vw = view_chain;
/* Check active window first */
if(curr_vw->vw_Tx == tx)
return(&curr_vw->vw_CursorPos);
while(vw)
{
if(vw->vw_Window && (vw->vw_Tx == tx))
return(&vw->vw_CursorPos);
vw = vw->vw_Next;
}
return(&tx->tx_SavedCPos);
}
/*
* returns the number of buffers saved.
* (maybe should only save one buffer at a time, then wait to be called
* again to save next in line? This could be less intrusive: yes.)
*/
int
auto_save_buffers(void)
{
/*
* Stops me entering here more than once at the same time. This
* can happen when tracing the `auto-save-function'
*/
static bool Exclusion;
if(!Exclusion)
{
VALUE tx = VAL(buffer_chain);
u_long time = sys_time();
Exclusion = TRUE;
while(tx)
{
if(VTX(tx)->tx_Changes
&& VTX(tx)->tx_AutoSaveInterval
&& (VTX(tx)->tx_LastSaveChanges != VTX(tx)->tx_Changes)
&& (time > (VTX(tx)->tx_LastSaveTime + VTX(tx)->tx_AutoSaveInterval)))
{
GCVAL gcv_tx;
PUSHGC(gcv_tx, tx);
call_lisp1(sym_auto_save_function, tx);
POPGC;
VTX(tx)->tx_LastSaveTime = time;
VTX(tx)->tx_LastSaveChanges = VTX(tx)->tx_Changes;
Exclusion = FALSE;
return(1);
}
tx = VAL(VTX(tx)->tx_Next);
}
Exclusion = FALSE;
}
return(0);
}
_PR VALUE cmd_current_buffer(VALUE);
DEFUN("current-buffer", cmd_current_buffer, subr_current_buffer, (VALUE vw), V_Subr1, DOC_current_buffer) /*
::doc:current_buffer::
current-buffer [WINDOW]
Return the buffer that WINDOW (or the current window) is displaying.
::end:: */
{
if(!WINDOWP(vw))
vw = VAL(curr_vw);
return(VAL(VWIN(vw)->vw_Tx));
}
_PR VALUE cmd_set_current_buffer(VALUE, VALUE);
DEFUN("set-current-buffer", cmd_set_current_buffer, subr_set_current_buffer, (VALUE tx, VALUE vw), V_Subr2, DOC_set_current_buffer) /*
::doc:set_current_buffer::
set-current-buffer BUFFER [WINDOW]
Set the buffer that WINDOW (or the current window) is displaying. Returns
the buffer which was being displayed before.
::end:: */
{
VALUE old;
DECLARE1(tx, BUFFERP);
if(!WINDOWP(vw))
vw = VAL(curr_vw);
old = VAL(VWIN(vw)->vw_Tx);
swap_buffers(VWIN(vw), VTX(tx));
return(old);
}
_PR VALUE cmd_buffer_file_name(VALUE);
DEFUN("buffer-file-name", cmd_buffer_file_name, subr_buffer_file_name, (VALUE tx), V_Subr1, DOC_buffer_file_name) /*
::doc:buffer_file_name::
buffer-file-name [BUFFER]
Return the name of the file being edited in BUFFER.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
return(VTX(tx)->tx_FileName);
}
_PR VALUE cmd_set_buffer_file_name(VALUE, VALUE);
DEFUN("set-buffer-file-name", cmd_set_buffer_file_name, subr_set_buffer_file_name, (VALUE tx, VALUE name), V_Subr2, DOC_set_buffer_file_name) /*
::doc:set_buffer_file_name::
set-buffer-file-name BUFFER NAME
Set the name of the file being edited in BUFFER to NAME.
::end:: */
{
DECLARE1(name, STRINGP);
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
make_marks_non_resident(VTX(tx));
VTX(tx)->tx_FileName = name;
make_marks_resident(VTX(tx));
return(name);
}
_PR VALUE cmd_buffer_name(VALUE);
DEFUN("buffer-name", cmd_buffer_name, subr_buffer_name, (VALUE tx), V_Subr1, DOC_buffer_name) /*
::doc:buffer_name::
buffer-name [BUFFER]
Return the name of BUFFER.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
return(VTX(tx)->tx_BufferName);
}
_PR VALUE cmd_set_buffer_name(VALUE, VALUE);
DEFUN("set-buffer-name", cmd_set_buffer_name, subr_set_buffer_name, (VALUE tx, VALUE name), V_Subr2, DOC_set_buffer_name) /*
::doc:set_buffer_name::
set-buffer-name BUFFER NAME
Set the name of BUFFER to NAME.
::end:: */
{
DECLARE1(name, STRINGP);
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
VTX(tx)->tx_BufferName = name;
sys_reset_sleep_titles(VTX(tx));
return(name);
}
_PR VALUE cmd_buffer_changes(VALUE);
DEFUN("buffer-changes", cmd_buffer_changes, subr_buffer_changes, (VALUE tx), V_Subr1, DOC_buffer_changes) /*
::doc:buffer_changes::
buffer-changes [BUFFER]
Return the number of modifications to BUFFER.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
return(make_number(VTX(tx)->tx_Changes));
}
_PR VALUE cmd_buffer_modified_p(VALUE);
DEFUN("buffer-modified-p", cmd_buffer_modified_p, subr_buffer_modified_p, (VALUE tx), V_Subr1, DOC_buffer_modified_p) /*
::doc:buffer_modified_p::
buffer-modified-p [BUFFER]
Returns t if the buffer has changed since it was last saved.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
/* TXFF_SPECIAL means this buffer's modifications aren't important. */
if(VTX(tx)->tx_Flags & TXFF_SPECIAL)
return(sym_nil);
if(VTX(tx)->tx_Changes != VTX(tx)->tx_ProperSaveChanges)
return(sym_t);
return(sym_nil);
}
_PR VALUE cmd_set_buffer_modified(VALUE, VALUE);
DEFUN("set-buffer-modified", cmd_set_buffer_modified, subr_set_buffer_modified, (VALUE tx, VALUE stat), V_Subr2, DOC_set_buffer_modified) /*
::doc:set_buffer_modified::
set-buffer-modified BUFFER STATUS
If STATUS is nil make it look as though buffer hasn't changed, else make
it look as though it has.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
if(NILP(stat))
{
VTX(tx)->tx_ProperSaveChanges = VTX(tx)->tx_Changes;
VTX(tx)->tx_LastSaveChanges = VTX(tx)->tx_Changes;
}
else
{
VTX(tx)->tx_ProperSaveChanges = VTX(tx)->tx_Changes - 1;
VTX(tx)->tx_LastSaveChanges = VTX(tx)->tx_Changes - 1;
}
return(tx);
}
_PR VALUE cmd_set_buffer_special(VALUE tx, VALUE specialp);
DEFUN("set-buffer-special", cmd_set_buffer_special, subr_set_buffer_special, (VALUE tx, VALUE specialp), V_Subr2, DOC_set_buffer_special) /*
::doc:set_buffer_special::
set-buffer-special BUFFER SPECIALP
When a buffer is `special' it means that it is controlled by some Lisp code,
not by the user typing into it (although this can still happen as well). This
is used for things like the `*jade*' or `*Info*' buffers (in fact most of
the buffers whose names are surrounded by asterisks are special).
What the `special' attribute actually does is make sure that the buffer is
never truely killed (`kill-buffer' removes it from each window's `buffer-list'
but doesn't detroy the actual contents) and modifications don't cause the
`+' marker to appear in the status line.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
if(NILP(specialp))
VTX(tx)->tx_Flags &= ~TXFF_SPECIAL;
else
VTX(tx)->tx_Flags |= TXFF_SPECIAL;
return(tx);
}
_PR VALUE cmd_buffer_special_p(VALUE tx);
DEFUN("buffer-special-p", cmd_buffer_special_p, subr_buffer_special_p, (VALUE tx), V_Subr1, DOC_buffer_special_p) /*
::doc:buffer_special_p::
buffer-special-p [BUFFER]
Returns t if BUFFER is ``special''. See `set-buffer-special' for the meaning of
the ``special'' attribute.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
if(VTX(tx)->tx_Flags & TXFF_SPECIAL)
return(sym_t);
return(sym_nil);
}
_PR VALUE cmd_set_buffer_read_only(VALUE tx, VALUE stat);
DEFUN("set-buffer-read-only", cmd_set_buffer_read_only, subr_set_buffer_read_only, (VALUE tx, VALUE stat), V_Subr2, DOC_set_buffer_read_only) /*
::doc:set_buffer_read_only::
set-buffer-read-only BUFFER READ-ONLY-P
If a buffer is read-only no modification of its contents is allowed.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
if(NILP(stat))
VTX(tx)->tx_Flags &= ~TXFF_RDONLY;
else
VTX(tx)->tx_Flags |= TXFF_RDONLY;
return(tx);
}
_PR VALUE cmd_buffer_read_only_p(VALUE tx);
DEFUN("buffer-read-only-p", cmd_buffer_read_only_p, subr_buffer_read_only_p, (VALUE tx), V_Subr1, DOC_buffer_read_only_p) /*
::doc:buffer_read_only_p::
buffer-read-only-p [BUFFER]
Returns t if BUFFER is read-only. See `set-buffer-read-only'.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
if(VTX(tx)->tx_Flags & TXFF_RDONLY)
return(sym_t);
return(sym_nil);
}
_PR VALUE cmd_buffer_length(VALUE);
DEFUN("buffer-length", cmd_buffer_length, subr_buffer_length, (VALUE tx), V_Subr1, DOC_buffer_length) /*
::doc:buffer_length::
buffer-length [BUFFER]
Returns the number of lines in BUFFER.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
return(make_number(VTX(tx)->tx_NumLines));
}
_PR VALUE cmd_line_length(VALUE, VALUE);
DEFUN("line-length", cmd_line_length, subr_line_length, (VALUE pos, VALUE tx), V_Subr2, DOC_line_length) /*
::doc:line_length::
line-length [LINE-POS] [BUFFER]
Returns the length (not including newline) of the specified line, or
using current cursor position if specifiers are not provided.
::end:: */
{
POS p;
if(POSP(pos))
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
p = VPOS(pos);
}
else
{
p = curr_vw->vw_CursorPos;
tx = VAL(curr_vw->vw_Tx);
}
return(make_number(VTX(tx)->tx_Lines[p.pos_Line].ln_Strlen - 1));
}
_PR VALUE cmd_with_buffer(VALUE);
DEFUN("with-buffer", cmd_with_buffer, subr_with_buffer, (VALUE args), V_SF, DOC_with_buffer) /*
::doc:with_buffer::
with-buffer BUFFER FORMS...
Temporarily switches to buffer, then executes the FORMS in it before
returning to the original buffer.
::end:: */
{
if(CONSP(args))
{
GCVAL gcv_args;
VALUE res;
PUSHGC(gcv_args, args);
if((res = cmd_eval(VCAR(args))) && BUFFERP(res))
{
VALUE oldtx = VAL(swap_buffers_tmp(curr_vw, VTX(res)));
if(oldtx)
{
GCVAL gcv_oldtx;
PUSHGC(gcv_oldtx, oldtx);
res = cmd_progn(VCDR(args));
POPGC;
swap_buffers_tmp(curr_vw, VTX(oldtx));
}
}
POPGC;
return(res);
}
return(NULL);
}
_PR VALUE cmd_bufferp(VALUE);
DEFUN("bufferp", cmd_bufferp, subr_bufferp, (VALUE arg), V_Subr1, DOC_bufferp) /*
::doc:bufferp::
bufferp ARG
Returns t if ARG is a buffer.
::end:: */
{
if(BUFFERP(arg))
return(sym_t);
return(sym_nil);
}
_PR VALUE var_auto_save_interval(VALUE);
DEFUN("auto-save-interval", var_auto_save_interval, subr_auto_save_interval, (VALUE val), V_Var, DOC_auto_save_interval) /*
::doc:auto_save_interval::
The number of modifications which must be made to a buffer before it
is considered for auto-saving. A value of zero means that this buffer
is not to be auto-saved.
::end:: */
{
return(handle_var_int(val, &curr_vw->vw_Tx->tx_AutoSaveInterval));
}
_PR VALUE var_last_save_changes(VALUE);
DEFUN("last-save-changes", var_last_save_changes, subr_last_save_changes, (VALUE val), V_Var, DOC_last_save_changes) /*
::doc:last_save_changes::
Number of changes the last time this buffer was saved (could be auto-save).
::end:: */
{
return(handle_var_int(val, &curr_vw->vw_Tx->tx_LastSaveChanges));
}
_PR VALUE var_last_user_save_changes(VALUE);
DEFUN("last-user-save-changes", var_last_user_save_changes, subr_last_user_save_changes, (VALUE val), V_Var, DOC_last_user_save_changes) /*
::doc:last_user_save_changes::
Number of changes the last time this buffer was saved (not from auto-save).
::end:: */
{
return(handle_var_int(val, &curr_vw->vw_Tx->tx_ProperSaveChanges));
}
_PR VALUE var_last_save_time(VALUE);
DEFUN("last-save-time", var_last_save_time, subr_last_save_time, (VALUE val), V_Var, DOC_last_save_time) /*
::doc:last_save_time::
System time at last save of this buffer (could be from an auto-save).
::end:: */
{
return(handle_var_int(val, &curr_vw->vw_Tx->tx_LastSaveTime));
}
_PR VALUE var_tab_size(VALUE);
DEFUN("tab-size", var_tab_size, subr_tab_size, (VALUE val), V_Var, DOC_tab_size) /*
::doc:tab_size::
Sets the size of tab-stops.
::end:: */
{
return(handle_var_int(val, &curr_vw->vw_Tx->tx_TabSize));
}
_PR VALUE var_mode_name(VALUE);
DEFUN("mode-name", var_mode_name, subr_mode_name, (VALUE val), V_Var, DOC_mode_name) /*
::doc:mode_name::
This is used to display the name of the edit-mode being used in the status
line.
::end:: */
{
TX *tx = curr_vw->vw_Tx;
if(val)
{
if(STRINGP(val))
tx->tx_ModeName = val;
else
tx->tx_ModeName = NULL;
return(val);
}
else if(tx->tx_ModeName)
return(tx->tx_ModeName);
return(sym_nil);
}
_PR VALUE var_minor_mode_names(VALUE);
DEFUN("minor-mode-names", var_minor_mode_names, subr_minor_mode_names, (VALUE val), V_Var, DOC_minor_mode_names) /*
::doc:minor_mode_names::
List of strings naming all minor-modes enabled in this buffer.
::end:: */
{
TX *tx = curr_vw->vw_Tx;
if(!val)
return(tx->tx_MinorModeNameList);
if(!CONSP(val))
val = sym_nil;
tx->tx_MinorModeNameList = val;
if(NILP(val))
tx->tx_MinorModeNameString = null_string;
else
{
int len;
u_char *str;
VALUE tmp = val;
for(len = 0; CONSP(tmp) && STRINGP(VCAR(tmp)); tmp = VCDR(tmp))
len += STRING_LEN(VCAR(tmp)) + 1;
tx->tx_MinorModeNameString = make_string(len + 1);
str = VSTR(tx->tx_MinorModeNameString);
tmp = val;
while(CONSP(tmp) && STRINGP(VCAR(tmp)))
{
*str++ = ' ';
str = stpcpy(str, VSTR(VCAR(tmp)));
tmp = VCDR(tmp);
}
}
return(val);
}
/* chain of all non-resident marks, linked via `mk_Next' */
static Mark *non_resident_mark_chain;
/* chain of all marks, linked via `mk_NextAlloc' */
static Mark *mark_chain;
/*
* For all non-resident marks, see if any point to NEWTX, if so link them
* onto NEWTX's `tx_Marks' chain.
*/
void
make_marks_resident(TX *newtx)
{
Mark *nxt, *mk = non_resident_mark_chain;
non_resident_mark_chain = NULL;
while(mk)
{
nxt = mk->mk_Next;
if(same_files(VSTR(newtx->tx_FileName), VSTR(mk->mk_File.name)))
{
mk->mk_File.tx = newtx;
mk->mk_Resident = TRUE;
mk->mk_Next = newtx->tx_MarkChain;
newtx->tx_MarkChain = mk;
}
else
{
mk->mk_Next = non_resident_mark_chain;
non_resident_mark_chain = mk;
}
mk = nxt;
}
}
void
make_marks_non_resident(TX *oldtx)
{
Mark *nxt, *mk = oldtx->tx_MarkChain;
oldtx->tx_MarkChain = NULL;
while(mk)
{
nxt = mk->mk_Next;
mk->mk_File.name = oldtx->tx_FileName;
mk->mk_Resident = FALSE;
mk->mk_Next = non_resident_mark_chain;
non_resident_mark_chain = mk;
mk = nxt;
}
}
/*
* Takes MK off the buffer mark chain that it's on (or the non_resident_mark_chain).
*/
static void
unchain_mark(Mark *mk)
{
Mark **headp, *this;
if(!mk->mk_Resident)
headp = &non_resident_mark_chain;
else
headp = &(mk->mk_File.tx->tx_MarkChain);
this = *headp;
*headp = NULL;
while(this)
{
Mark *tmp = this->mk_Next;
if(this != mk)
{
this->mk_Next = *headp;
*headp = this;
}
this = tmp;
}
}
void
mark_sweep(void)
{
Mark *mk = mark_chain;
mark_chain = NULL;
while(mk)
{
Mark *nxt = mk->mk_NextAlloc;
if(!GC_MARKEDP(VAL(mk)))
{
unchain_mark(mk);
str_free(mk);
}
else
{
GC_CLR(VAL(mk));
mk->mk_NextAlloc = mark_chain;
mark_chain = mk;
}
mk = nxt;
}
}
int
mark_cmp(VALUE v1, VALUE v2)
{
int rc = 1;
if(VTYPE(v1) == VTYPE(v2))
{
u_char *name1, *name2;
if(VMARK(v1)->mk_Resident)
name1 = VSTR(VMARK(v1)->mk_File.tx->tx_FileName);
else
name1 = VSTR(VMARK(v1)->mk_File.name);
if(VMARK(v2)->mk_Resident)
name2 = VSTR(VMARK(v2)->mk_File.tx->tx_FileName);
else
name2 = VSTR(VMARK(v2)->mk_File.name);
if(same_files(name1, name2))
{
if(!(rc = VPOS(VMARK(v1)->mk_Pos).pos_Line - VPOS(VMARK(v2)->mk_Pos).pos_Line))
rc = VPOS(VMARK(v1)->mk_Pos).pos_Col - VPOS(VMARK(v2)->mk_Pos).pos_Col;
}
}
return(rc);
}
void
mark_prin(VALUE strm, VALUE obj)
{
u_char tbuf[40];
stream_puts(strm, "#<mark ", -1, FALSE);
if(VMARK(obj)->mk_Resident)
buffer_prin(strm, VAL(VMARK(obj)->mk_File.tx));
else
{
stream_putc(strm, '"');
stream_puts(strm, VSTR(VMARK(obj)->mk_File.name), -1, TRUE);
stream_putc(strm, '"');
}
sprintf(tbuf, " #<pos %ld %ld>>",
VPOS(VMARK(obj)->mk_Pos).pos_Col,
VPOS(VMARK(obj)->mk_Pos).pos_Line);
stream_puts(strm, tbuf, -1, FALSE);
}
_PR VALUE cmd_make_mark(VALUE, VALUE);
DEFUN("make-mark", cmd_make_mark, subr_make_mark, (VALUE pos, VALUE buffer), V_Subr2, DOC_make_mark) /*
::doc:make_mark::
make-mark [POS] [BUFFER | FILE-NAME]
Creates a new mark pointing to position POS either in the current file
or in FILE-NAME, or BUFFER.
Note that FILE-NAME doesn't have to be a file that has been loaded, it's
stored as a string, the file it points to is only opened when needed.
Unlike position objects, the position in a file that a mark points to is
updated as the file changes -- it will always point to the same character
(for as long as that character exists, anyway).
::end:: */
{
Mark *mk = NULL;
if((mk = str_alloc(sizeof(Mark))) && (mk->mk_Pos = make_lpos(NULL)))
{
mk->mk_Type = V_Mark;
mk->mk_NextAlloc = mark_chain;
mark_chain = mk;
data_after_gc += sizeof(Mark);
if(POSP(pos))
VPOS(mk->mk_Pos) = VPOS(pos);
else
VPOS(mk->mk_Pos) = curr_vw->vw_CursorPos;
if(STRINGP(buffer))
{
VALUE tx;
if((tx = cmd_get_file_buffer(buffer)) && BUFFERP(tx))
{
mk->mk_Resident = TRUE;
mk->mk_File.tx = VTX(tx);
mk->mk_Next = VTX(tx)->tx_MarkChain;
VTX(tx)->tx_MarkChain = mk;
}
else
{
mk->mk_Resident = FALSE;
mk->mk_File.name = buffer;
mk->mk_Next = non_resident_mark_chain;
non_resident_mark_chain = mk;
}
}
else
{
if(!BUFFERP(buffer))
buffer = VAL(curr_vw->vw_Tx);
mk->mk_Resident = TRUE;
mk->mk_File.tx = VTX(buffer);
mk->mk_Next = VTX(buffer)->tx_MarkChain;
VTX(buffer)->tx_MarkChain = mk;
}
return(VAL(mk));
}
if(mk)
str_free(mk);
return(NULL);
}
_PR VALUE cmd_set_mark(VALUE, VALUE, VALUE);
DEFUN("set-mark", cmd_set_mark, subr_set_mark, (VALUE mark, VALUE pos, VALUE buffer), V_Subr3, DOC_set_mark) /*
::doc:set_mark::
set-mark MARK [POS] [FILE-NAME | BUFFER]
Sets the position which MARK points to POS in FILE-NAME or BUFFER.
::end:: */
{
DECLARE1(mark, MARKP);
if(POSP(pos))
VPOS(VMARK(mark)->mk_Pos) = VPOS(pos);
if(BUFFERP(buffer) || STRINGP(buffer))
{
Mark *mk, **chain;
if(VMARK(mark)->mk_Resident)
chain = &(VMARK(mark)->mk_File.tx->tx_MarkChain);
else
chain = &non_resident_mark_chain;
mk = *chain;
*chain = NULL;
while(mk)
{
Mark *nxt = mk->mk_Next;
if(mk != VMARK(mark))
{
mk->mk_Next = *chain;
*chain = mk;
}
else
mk->mk_Next = NULL;
mk = nxt;
}
VMARK(mark)->mk_File.name = buffer;
switch(VTYPE(buffer))
{
VALUE tmp;
case V_StaticString:
case V_DynamicString:
tmp = cmd_get_file_buffer(buffer);
if((tmp == NULL) || NILP(tmp))
{
VMARK(mark)->mk_Resident = FALSE;
VMARK(mark)->mk_Next = non_resident_mark_chain;
non_resident_mark_chain = VMARK(mark);
break;
}
VMARK(mark)->mk_File.name = tmp;
/* FALL THROUGH */
case V_TX:
VMARK(mark)->mk_Resident = TRUE;
VMARK(mark)->mk_Next = VMARK(mark)->mk_File.tx->tx_MarkChain;
VMARK(mark)->mk_File.tx->tx_MarkChain = VMARK(mark);
break;
}
}
return(mark);
}
_PR VALUE cmd_mark_pos(VALUE);
DEFUN("mark-pos", cmd_mark_pos, subr_mark_pos, (VALUE mark), V_Subr1, DOC_mark_pos) /*
::doc:mark_pos::
mark-pos MARK
Returns the position that MARK points to. (note that this is the *same*
object that the mark stores internally -- so don't modify it unless you're
really sure you know what you're doing)
::end:: */
{
DECLARE1(mark, MARKP);
return(VMARK(mark)->mk_Pos);
}
_PR VALUE cmd_mark_file(VALUE);
DEFUN("mark-file", cmd_mark_file, subr_mark_file, (VALUE mark), V_Subr1, DOC_mark_file) /*
::doc:mark_file::
mark-file MARK
Returns the file-name or buffer that MARK points to.
::end:: */
{
DECLARE1(mark, MARKP);
return(VMARK(mark)->mk_File.name);
}
_PR VALUE cmd_mark_resident_p(VALUE);
DEFUN("mark-resident-p", cmd_mark_resident_p, subr_mark_resident_p, (VALUE mark), V_Subr1, DOC_mark_resident_p) /*
::doc:mark_resident_p::
mark-resident-p MARK
Returns t if the file that MARK points to is in a buffer.
::end:: */
{
DECLARE1(mark, MARKP);
if(VMARK(mark)->mk_Resident)
return(sym_t);
return(sym_nil);
}
_PR VALUE cmd_markp(VALUE);
DEFUN("markp", cmd_markp, subr_markp, (VALUE mark), V_Subr1, DOC_markp) /*
::doc:markp::
markp ARG
Return t if ARG is a mark.
::end:: */
{
if(MARKP(mark))
return(sym_t);
return(sym_nil);
}
void
buffers_init(void)
{
mark_static((VALUE *)&non_resident_mark_chain);
INTERN(sym_auto_save_function, "auto-save-function");
INTERN(sym_leading, "leading");
INTERN(sym_all, "all");
ADD_SUBR(subr_make_buffer_name);
ADD_SUBR(subr_make_buffer);
ADD_SUBR(subr_destroy_buffer);
ADD_SUBR(subr_get_file_buffer);
ADD_SUBR(subr_get_buffer);
ADD_SUBR(subr_current_buffer);
ADD_SUBR(subr_set_current_buffer);
ADD_SUBR(subr_buffer_file_name);
ADD_SUBR(subr_set_buffer_file_name);
ADD_SUBR(subr_buffer_name);
ADD_SUBR(subr_set_buffer_name);
ADD_SUBR(subr_buffer_changes);
ADD_SUBR(subr_buffer_modified_p);
ADD_SUBR(subr_set_buffer_modified);
ADD_SUBR(subr_set_buffer_special);
ADD_SUBR(subr_buffer_special_p);
ADD_SUBR(subr_set_buffer_read_only);
ADD_SUBR(subr_buffer_read_only_p);
ADD_SUBR(subr_buffer_length);
ADD_SUBR(subr_line_length);
ADD_SUBR(subr_with_buffer);
ADD_SUBR(subr_bufferp);
ADD_SUBR(subr_auto_save_interval);
ADD_SUBR(subr_last_save_changes);
ADD_SUBR(subr_last_user_save_changes);
ADD_SUBR(subr_last_save_time);
ADD_SUBR(subr_tab_size);
ADD_SUBR(subr_mode_name);
ADD_SUBR(subr_minor_mode_names);
ADD_SUBR(subr_make_mark);
ADD_SUBR(subr_set_mark);
ADD_SUBR(subr_mark_pos);
ADD_SUBR(subr_mark_file);
ADD_SUBR(subr_mark_resident_p);
ADD_SUBR(subr_markp);
}
void
buffers_kill(void)
{
TX *tx = buffer_chain;
Mark *mk = mark_chain;
while(tx)
{
TX *nxttx = tx->tx_Next;
kill_line_list(tx);
myfree(tx);
tx = nxttx;
}
buffer_chain = NULL;
while(mk)
{
Mark *nxtmk = mk->mk_NextAlloc;
str_free(mk);
mk = nxtmk;
}
mark_chain = NULL;
}